using namespace std;
#pragma once
#include "includes.h"


template <class type>

class vector3
{
public:
    type x,y,z;
    vector3<type>(type, type, type);
    vector3<type>(const vector3<type>& v);
    vector3<type>(void);
    ~vector3(void) {}


    type    dot(vector3<type>& v);
    vector3<type> cross(vector3<type>& v);
    vector3<type> unit();
	float    mag();
    float    magsqr();
    void print();

    bool operator<(const vector3<type> b) const;
    bool operator==(const vector3<type>& b) const;
    bool operator!=(const vector3<type>& b) const;
    bool operator > (vector3<type> b);
    bool operator >= (vector3<type> b);
    vector3<type> operator*(type);		//scalar mul
    vector3<type> operator/(type);		//scalar divide
    vector3<type> operator+(vector3<type> v);//add
    vector3<type> operator-(vector3<type> v);//subtract
    vector3<type>& operator*=(type);		//scalar mul equal
    vector3<type>& operator/=(type);		//scalar divide equal
    vector3<type>& operator+=(vector3<type> v);//add equal
    vector3<type>& operator-=(vector3<type> v);//subtract equal
    vector3<type> operator-();			 //inverse
    vector3<type> operator~();			 //unit

    vector3<type> rotateX(float angle);
    vector3<type> rotateY(float angle);
    vector3<type> rotateZ(float angle);

    vector3<type> intersection(vector3<type> a);

    bool between(vector3<type>& a, vector3<type>& b);


    template <class type2>
        vector3<type2> cast();

};

//template <class type>
//inline
//string vector3<type>::stringKey(vector3<type>) {
//    ostringstream convert;
//}

template <class type>
template <class type2>
inline
vector3<type2> vector3<type>::cast(){
    return vector3<type2>((type2)x,(type2)y,(type2)z);
}


template <class type>
inline
vector3<type>::vector3(type _x, type _y, type _z)
{
    x=_x;
    y=_y;
    z=_z;
}

template <class type>
inline
vector3<type>::vector3(void){
    x=y=z=0;
}

template <class type>
inline
vector3<type>::vector3(const vector3<type>& v){
    x=v.x;
    y=v.y;
    z=v.z;
}

template <class type>
inline
void vector3<type>::print() {
    cout << x <<", " << y << ", " << z << "\n";
}

template <class type>
inline
type vector3<type>::dot(vector3<type>& v){
    return x * v.x + y * v.y + z * v.z;
}

template <class type>
inline
vector3<type> vector3<type>::cross(vector3<type>& v){
    return vector3<type>(y * v.z - v.y * z, z * v.x - v.z * x, x * v.y - v.x * y);
}

template <class type>
inline
vector3<type> vector3<type>::unit(){
float m=mag();
return vector3<type>(x/m, y/m, z/m);
}


template <class type>
bool vector3<type>::operator<(const vector3<type> b) const{
    return (x < b.x ||(x == b.x && y < b.y) || (x == b.x && y == b.y && z < b.z));
}


template <class type>
bool vector3<type>::operator>(vector3<type> b) {
    return (x > b.x && y > b.y && z > b.z);
}

template <class type>
bool vector3<type>::operator>=(vector3<type> b) {
    return (x >= b.x && y >= b.y && z >= b.z);
}


template <class type>
inline
bool vector3<type>::operator==(const vector3<type>& b) const{
    return (x == b.x && y == b.y && z == b.z);
}

template <class type>
inline
bool vector3<type>::operator!=(const vector3<type>& b) const{
    return (x != b.x || y != b.y || z != b.z);
}

template <class type>
inline
vector3<type> vector3<type>::operator~(){
    return unit();
}
template <class type>
inline
vector3<type> vector3<type>::operator*(type k){
    return vector3<type>(x*k,y*k,z*k);
}
template <class type>
inline
vector3<type> vector3<type>::operator/(type k){
    return vector3<type>(x/k,y/k,z/k);
}

template <class type>
inline
vector3<type> vector3<type>::operator+(vector3<type> v){
    return vector3<type>(x+v.x,y+v.y,z+v.z);
}

template <class type>
inline
vector3<type> vector3<type>::operator-(vector3<type> v){
    return vector3<type>(x-v.x,y-v.y,z-v.z);
}

template <class type>
inline
vector3<type> vector3<type>::operator-(){
    return vector3<type>(-x, -y, -z);
}

template <class type>
inline
vector3<type>& vector3<type>::operator*=(type k){
    return *this = (*this) * k;
}


template <class type>
inline
vector3<type>& vector3<type>::operator/=(type k){
    return *this = (*this) / k;
}


template <class type>
inline
vector3<type>& vector3<type>::operator+=(vector3<type> v){
    return *this = (*this) + v;
}

template <class type>
inline
vector3<type>& vector3<type>::operator-=(vector3<type> v){
    return *this = (*this) - v;
}


template <class type>
inline
float vector3<type>::mag(){
    return sqrt((float) (x*x+y*y+z*z));
}

template <class type>
inline
float vector3<type>::magsqr(){
    return x*x+y*y+z*z;
}

template <class type>
inline
vector3<type> vector3<type>::rotateX(float angle){
    this->x=this->x;
    this->y=this->y*cos(angle) - this->z*sin(angle);
    this->z=this->y*sin(angle) + this->z*cos(angle);
    return (*this);
}

template <class type>
inline
vector3<type> vector3<type>::rotateY(float angle){
    this->x=this->x*cos(angle) + this->z*sin(angle);
    this->y=this->y;
    this->z=-this->x*sin(angle) + this->z*cos(angle);
    return (*this);
}

template <class type>
inline
vector3<type> vector3<type>::rotateZ(float angle){
    this->x=this->x*cos(angle) - this->y*sin(angle);
    this->y=this->x*sin(angle) + this->y*cos(angle);
    this->z=this->z;
    return (*this);
}

template <class type>
inline
bool vector3<type>::between(vector3<type>& a, vector3<type>& b) {
    return ((this->x >= a.x && this->x <= b.x
            && this->y >= a.y && this->y <= b.y
            && this->z >= a.z && this->z <= b.z) ||
            (this->x <= a.x && this->x >= b.x
                        && this->y < a.y && this->y >= b.y
                        && this->z < a.z && this->z >= b.z));
}

template <class type>
inline
vector3<type> vector3<type>::intersection(vector3<type> a){

}
